// PARADIME INTERPRETER
//
//LICENSED FREELY UNDER MIT.
//CREATED FOR FREE USE.

#include "stdafx.h"
#include "tokentypes.h"
#include "Interpreter.h"
#include "variabledomain.h"
#include "variant.h"
#include "Parser.h"
#include "errorcodes.h"


typedef int (*builtin)(token*,std::vector<token>*,Interpreter* CodeOwner);


//This is called to process the tokens making up a function call, and execute that call.
//it sets token* result with the result and unwinds back to the parser.
//NOTE: in collecting the params for the func call, it will eval each func parameter
//an expression, therefore unwinding any nested structures, like nested function calls.
int Parser_FuncCallExec(token* result,std::vector<token>* exp, int* iterator, Interpreter* CodeOwner)
{
	//Default return values
	result->type = OPT_INT32_TOK;
	result->nValue = 0;

	//Important Vars
	int i = *iterator; //Get past 'FUNCNAME' '(' tokens
	std::vector<token> params; //Stores the evaluated functions in prep for everything.
	std::vector<token> tempparamexp; //Stores the expression for the param prior to evaluation.
	std::string funcname = (*exp)[i].data;

	i+= 2;

	//Vars needed to keep track of iterations and position in a potentially recursive expression.
	int bracketlevel = 1;
	
	while(bracketlevel > 0){
		token Currenttoken = (*exp)[i];

		if(Currenttoken.type == LFT_BRACKET_TOK)
			bracketlevel++;
		else if(Currenttoken.type == RHT_BRACKET_TOK)
			bracketlevel--;

		if(bracketlevel==0)break;

		if((bracketlevel > 1) || (Currenttoken.type != PARAM_SEPARATOR_TOK))
		{
			tempparamexp.push_back( Currenttoken);
		}
		else if((bracketlevel == 1) && (Currenttoken.type == PARAM_SEPARATOR_TOK))
		{
			//We now have the full expression, lets evaluate, pushing the result to the stack.
			params.push_back( EvaluateRPN(ShuntExpression(&tempparamexp,CodeOwner),CodeOwner));
			while(tempparamexp.size())tempparamexp.pop_back(); //Empty the expression array for the next stack.
		}
		i++;
	}


	//The last parameter has not been evaluated and is still on the expression array.
	if(tempparamexp.size())
		params.push_back( EvaluateRPN(ShuntExpression(&tempparamexp,CodeOwner),CodeOwner));

	//Now we have all the parameters and everything is in order.
	//Find and execute the function.
	void* pfunc = LookupBuiltin(CodeOwner, funcname);
	if(pfunc == 0)
		return BUILTIN_ERR_FUNCNOTFOUND;
	int (*built)(token* ,std::vector<token>*,Interpreter* CodeOwner) = (builtin)pfunc;

	*iterator = i;
	return built( result, &params, CodeOwner);
}


//This function takes a pointer to an interpreters builtin function pointer table,
//and sets the default function pointers.
void InitBuiltinTable_Defaults(std::map<std::string,int (*)(token* ,std::vector<token>*,Interpreter* CodeOwner)>* table)
{
	//Stream IO
	(*table)["CONSOLEWRITE"] = Builtin_ConsoleWrite;
	(*table)["MSGBOX"] = Builtin_MsgBox;
	//String functions
	(*table)["STRINGLEN"] =  Builtin_StringLen;
	(*table)["STRINGLEFT"] =  Builtin_StringLeft;
	(*table)["STRINGRIGHT"] =  Builtin_StringRight;
	(*table)["STRINGMID"] =  Builtin_StringMid;
	(*table)["STRINGTRIMLEFT"] = Builtin_StringTrimLeft;
	(*table)["STRINGTRIMRIGHT"] = Builtin_StringTrimRight;
	//File IO
	(*table)["FILEOPEN"] = Builtin_FileOpen;
	(*table)["FILECLOSE"]= Builtin_FileClose;
	(*table)["FILEREAD"] = Builtin_FileRead;
	//Misc
	(*table)["TIMERINIT"] = Builtin_TimerInit;
	(*table)["TIMERDIFF"] = Builtin_TimerDiff;
}

//returns the function pointer of a builtin function, given the name.
//returns 0 if not found.
void* LookupBuiltin(Interpreter* CodeOwner, std::string name)
{
	std::map<std::string,int (*)(token* ,std::vector<token>*,Interpreter* CodeOwner)>* table = &CodeOwner->BuiltinTable;
	std::map<std::string,int (*)(token* ,std::vector<token>*,Interpreter* CodeOwner)>::iterator iTemp = table->find(name);
	if(iTemp == table->end()) //ERROR!: Function not in table.
		return (void*)0;
	else
		return (void*)iTemp->second;
}


void Token_ForceDoubleType( token* tok){
	Variant* vTemp;
	__int64 i64Temp;
	double fTemp;

	int iType = tok->type;
	tok->type = OPT_DOUBLE_TOK;
	switch(iType){
		case OPT_INT32_TOK:
			fTemp = (double)tok->nValue;
			tok->fValue = fTemp;
			return;
			break;
		case OPT_INT64_TOK:
			fTemp = (double)tok->n64Value;
			tok->fValue = fTemp;
			break;
		case OPT_DOUBLE_TOK:
			return;
			break;
		case OPT_STRINGLITERAL_TOK:
			tok->fValue = atof( tok->szValue);
			break;
		case PARSER_VARIABLE:
			vTemp = tok->ResolvedVariable;
			tok->nValue = vTemp->GetDouble();
			return;
			break;
	}

}

void Token_ForceInt32Type( token* tok){
	Variant* vTemp;
	__int64 i64Temp;
	double fTemp;

	int iType = tok->type;
	tok->type = OPT_INT32_TOK;
	switch(iType){
		case OPT_INT32_TOK:
			return;
			break;
		case OPT_INT64_TOK:
			i64Temp = tok->n64Value;
			tok->nValue = (int)i64Temp;
			break;
		case OPT_DOUBLE_TOK:
			fTemp = tok->fValue;
			tok->nValue = (int)fTemp;
			break;
		case OPT_STRINGLITERAL_TOK:
			tok->nValue = atoi( tok->szValue);
			break;
		case PARSER_VARIABLE:
			vTemp = tok->ResolvedVariable;
			tok->nValue = vTemp->GetInt32();
			return;
			break;
	}
}

//This function is for use by builtin functions.
void Token_ForceStrType( token* tok){
	std::ostringstream sTemp;
	sTemp.precision(15);
	Variant* vTemp;

	int iType = tok->type;
	tok->type = OPT_STRINGLITERAL_TOK;
	switch(iType){
		case OPT_INT32_TOK:
			sTemp << tok->nValue;
			break;
		case OPT_INT64_TOK:
			sTemp << tok->n64Value;
			break;
		case OPT_DOUBLE_TOK:
			sTemp << tok->fValue;
			break;
		case OPT_STRINGLITERAL_TOK:
			return;
			break;
		case PARSER_VARIABLE:
			vTemp = tok->ResolvedVariable;
			tok->szValue = vTemp->GetString();
			return;
			break;
	}

	tok->szValue = new char[strlen(sTemp.str().c_str())+1];
	strcpy(tok->szValue, sTemp.str().c_str());
}

